#!/usr/bin/env ts-node

/**
 * Enterprise monitoring example of @roasmax/rabbitmq
 */

import {
  RabbitMQClient,
  createHealthChecker,
  createMonitoringSystem,
  AlertSeverity,
  createFunctionHandler,
  createLoggingMiddleware,
  createMetricsMiddleware,
} from '../src';

async function monitoringExample(): Promise<void> {
  console.log('🔍 RabbitMQ Enterprise Monitoring Example');
  console.log('=========================================');

  // Create client with monitoring configuration
  const client = RabbitMQClient.create({
    host: process.env.RABBITMQ_HOST || 'localhost',
    port: parseInt(process.env.RABBITMQ_PORT || '5672'),
    username: process.env.RABBITMQ_USERNAME || 'guest',
    password: process.env.RABBITMQ_PASSWORD || 'guest',
  });

  try {
    await client.initialize();
    console.log('✅ Client initialized');

    // Setup middleware for monitoring
    const pipeline = client.getMiddlewarePipeline();
    pipeline.add(createLoggingMiddleware({ logLevel: 'info' }));
    
    const metricsMiddleware = createMetricsMiddleware();
    pipeline.add(metricsMiddleware);

    // Get connection pool for health checking
    const connectionPool = (client as any).connectionPool;

    // Create health checker
    const healthChecker = createHealthChecker(connectionPool, {
      memoryThreshold: 256, // 256MB threshold for demo
    });

    // Create monitoring system
    const monitoring = createMonitoringSystem(healthChecker, {
      healthCheckInterval: 10000, // Check every 10 seconds
      alertThresholds: {
        memoryUsage: 70, // Alert at 70% memory usage
        connectionFailures: 3,
        messageBacklog: 100,
        processingLatency: 2000,
      },
    });

    // Set up event listeners
    monitoring.on('started', () => {
      console.log('🚀 Monitoring system started');
    });

    monitoring.on('healthCheck', (healthStatus) => {
      console.log(`💓 Health check: ${healthStatus.status} (${new Date(healthStatus.timestamp).toLocaleTimeString()})`);
      
      if (healthStatus.status !== 'healthy') {
        console.log(`  Connection: ${healthStatus.checks.connection.status}`);
        console.log(`  Memory: ${healthStatus.checks.memory.usage}MB / ${healthStatus.checks.memory.limit}MB`);
      }
    });

    monitoring.on('alert', (alert) => {
      const emoji = {
        [AlertSeverity.INFO]: 'ℹ️',
        [AlertSeverity.WARNING]: '⚠️',
        [AlertSeverity.ERROR]: '❌',
        [AlertSeverity.CRITICAL]: '🚨',
      }[alert.severity];

      console.log(`${emoji} ALERT [${alert.severity.toUpperCase()}]: ${alert.title}`);
      console.log(`   ${alert.message}`);
      console.log(`   Source: ${alert.source} | Time: ${new Date(alert.timestamp).toLocaleTimeString()}`);
    });

    monitoring.on('alertResolved', (alert) => {
      console.log(`✅ RESOLVED: ${alert.title}`);
    });

    // Start monitoring
    monitoring.start();

    // Create some workload to monitor
    console.log('\n📋 Creating workload for monitoring...');
    
    const workQueue = client.createWorkQueue('monitoring_test');
    await workQueue.setupQueue();

    // Create a handler that sometimes fails to generate alerts
    const testHandler = createFunctionHandler(async (data: any) => {
      const processingTime = Math.random() * 3000; // 0-3 seconds
      await new Promise(resolve => setTimeout(resolve, processingTime));
      
      // Record custom metrics
      monitoring.recordMetric('task_processing_time', processingTime);
      monitoring.recordMetric('tasks_processed', 1);
      
      // Simulate occasional failures
      if (Math.random() < 0.1) { // 10% failure rate
        throw new Error('Simulated processing failure');
      }
      
      console.log(`  ✅ Processed task ${data.id} in ${processingTime.toFixed(0)}ms`);
      return { processed: true, processingTime };
    });

    // Start workers
    await workQueue.startWorkers(testHandler, 2);

    // Send test tasks
    console.log('📤 Sending test tasks...');
    for (let i = 1; i <= 20; i++) {
      await workQueue.sendTask({
        id: i,
        type: 'test_task',
        timestamp: new Date().toISOString(),
      });
      
      // Small delay between tasks
      await new Promise(resolve => setTimeout(resolve, 500));
    }

    // Let the system run and monitor for a while
    console.log('\n⏳ Monitoring system for 60 seconds...');
    await new Promise(resolve => setTimeout(resolve, 60000));

    // Simulate high memory usage to trigger alerts
    console.log('\n🧪 Simulating high memory usage...');
    const memoryHog: any[] = [];
    for (let i = 0; i < 1000; i++) {
      memoryHog.push(new Array(10000).fill('memory-test-data'));
    }

    // Wait for memory alert
    await new Promise(resolve => setTimeout(resolve, 15000));

    // Clean up memory
    memoryHog.length = 0;
    global.gc && global.gc(); // Force garbage collection if available

    // Display monitoring results
    console.log('\n📊 Monitoring Results');
    console.log('=====================');

    // Health status
    const finalHealth = await healthChecker.checkHealth();
    console.log(`Final health status: ${finalHealth.status}`);
    console.log(`System uptime: ${(finalHealth.uptime / 1000).toFixed(1)} seconds`);

    // Connection stats
    const connectionStats = healthChecker.getConnectionStats();
    console.log(`\nConnection pool stats:`);
    console.log(`  Total connections: ${connectionStats.totalConnections}`);
    console.log(`  Available: ${connectionStats.availableConnections}`);
    console.log(`  Busy: ${connectionStats.busyConnections}`);

    // System info
    const systemInfo = healthChecker.getSystemInfo();
    console.log(`\nSystem info:`);
    console.log(`  Node.js: ${systemInfo.nodeVersion}`);
    console.log(`  Platform: ${systemInfo.platform} ${systemInfo.arch}`);
    console.log(`  Memory usage: ${Math.round(systemInfo.memory.heapUsed / 1024 / 1024)}MB`);

    // Monitoring status
    const monitoringStatus = monitoring.getStatus();
    console.log(`\nMonitoring status:`);
    console.log(`  Active alerts: ${monitoringStatus.activeAlerts}`);
    console.log(`  Alerts by severity:`);
    Object.entries(monitoringStatus.alertsBySeverity).forEach(([severity, count]) => {
      if (count > 0) {
        console.log(`    ${severity}: ${count}`);
      }
    });

    // Custom metrics
    const customMetrics = monitoring.getAllMetrics();
    console.log(`\nCustom metrics:`);
    Object.entries(customMetrics).forEach(([name, stats]) => {
      if (stats) {
        console.log(`  ${name}:`);
        console.log(`    Count: ${stats.count}`);
        console.log(`    Average: ${stats.avg.toFixed(2)}`);
        console.log(`    Min/Max: ${stats.min.toFixed(2)} / ${stats.max.toFixed(2)}`);
      }
    });

    // Message processing metrics
    const messageMetrics = metricsMiddleware.getDetailedMetrics();
    console.log(`\nMessage processing metrics:`);
    console.log(`  Messages sent: ${messageMetrics.basic.sentCount}`);
    console.log(`  Messages processed: ${messageMetrics.basic.processedCount}`);
    console.log(`  Messages failed: ${messageMetrics.basic.failedCount}`);
    console.log(`  Success rate: ${(messageMetrics.rates.successRate * 100).toFixed(1)}%`);
    console.log(`  Average processing time: ${messageMetrics.basic.averageProcessingTime.toFixed(2)}ms`);

    // Active alerts
    const activeAlerts = monitoring.getActiveAlerts();
    if (activeAlerts.length > 0) {
      console.log(`\nActive alerts:`);
      activeAlerts.forEach(alert => {
        console.log(`  [${alert.severity.toUpperCase()}] ${alert.title}: ${alert.message}`);
      });
    }

    console.log('\n✅ Monitoring example completed!');

  } catch (error) {
    console.error('❌ Monitoring example error:', error);
  } finally {
    // Clean up
    await client.close();
    console.log('🔒 Client closed');
  }
}

// Run the example
if (require.main === module) {
  monitoringExample().catch(console.error);
}

export { monitoringExample };
